﻿using System;
using System.Data;
using System.Data.SqlClient;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using RestService.Processing;
using System.Drawing;
using System.Diagnostics;

namespace RestService
{
    public class RestServiceImpl : IRestServiceImpl
    {
        const string connStr = "server=.;uid=sa;pwd=sa;database=minipassport";
        public static int _KNN = 4;
        public static int _TopAP_RSSmax = 5;
        public static int _topAPCalculate = 0;

        public string XMLData(string id)
        {
            return "You requested product " + id;
        }

        public string JSONData(string id)
        {
            return "You requested product " + id;
        }

        public string ReturnEmail(string user)
        {
            SqlConnection dbConn = new SqlConnection(connStr);
            string sqlStr = "Select email from [users] where username = '" + user + "';";
            dbConn.Open();
            SqlCommand dbCommand = new SqlCommand(sqlStr, dbConn);
            SqlDataReader dbReader = dbCommand.ExecuteReader();
            dbReader.Read();
            string _name = dbReader[0].ToString();
            dbReader.Close();
            dbConn.Close();
            return _name;
        }

        /// <summary>
        /// Offline
        /// </summary>
        /// <returns></returns>
        public void InsertAP(RequestData rData)
        {
            try
            {
                var data = rData.details.Split('|');
                var response = new APService
                {
                    MAC = data[1],
                    Name = data[0]
                };

                AP apNew = DanhMucAP.Instance.GetByMAC(data[1]);
                if (apNew == null)
                {
                    apNew = DanhMucAP.Instance.NewDoiTuong();
                    apNew.Name = data[0];
                    apNew.MAC = data[1];
                    apNew.InsertToDB();
                }
                else
                {
                    apNew.Name = data[0];
                    apNew.UpdateToDB();
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            // return response;
        }
        public string InsertJsonAP(RequestData rData)
        {
            InsertAP(rData);
            return "OK";
        }

        public void InsertGroupAP(RequestGroupAP rGroupAP)
        {
            try
            {
                var data = rGroupAP.APdetails.Split('|');
                var point = data[0].Split(',');

                decimal toaDoX = 0;
                decimal toaDoY = 0;
                string Direct = "";
                decimal Degree = -1000;

                decimal.TryParse(point[0].ToString(), out toaDoX);
                decimal.TryParse(point[1].ToString(), out toaDoY);
                Direct = point[2].ToString();
                decimal.TryParse(point[3].ToString(), out Degree);
                List<APInfo> apInfoInput = new List<APInfo>();

                var APs = data[1].Split('@');

                for (int i = 0; i < APs.Length; i++)
                {
                    var detail = APs[i].Split(',');
                    APInfo ap = new APInfo();
                    AP apMAC = DanhMucAP.Instance.GetByMAC(detail[1]);

                    ap.ID = apMAC.ID;
                    ap.Name = detail[0];
                    ap.MAC = detail[1];
                    ap.RSS = Convert.ToInt32(detail[2]);
                    apInfoInput.Add(ap);
                }

                List<APInfo> apInfos = new List<APInfo>();

                if (apInfoInput.Count > 10)
                {
                    apInfos = apInfoInput.OrderByDescending(x => x.RSS).Take(10).ToList();
                }
                else
                    apInfos = apInfoInput.ToList();

                RestService.Processing.Point newPoint = DanhMucPoint.Instance.NewDoiTuong();
                newPoint.X = (decimal)toaDoX;
                newPoint.Y = (decimal)toaDoY;
                newPoint.Direct = Direct;
                newPoint.InsertToDB();
                foreach (APInfo apInfo in apInfos)
                {
                    //Lưu signal tương ứng với các AP
                    GroupAP signal = DanhMucGroupAP.Instance.NewDoiTuong();
                    signal.AID = apInfo.ID;
                    signal.RSS = apInfo.RSS;
                    signal.PID = newPoint.ID;
                    signal.InsertToDB();

                }
                //newGroupAP.InsertToDB();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public string InsertJsonGroupAP(RequestGroupAP rGroupAP)
        {
            InsertGroupAP(rGroupAP);
            return "Insert Successed";
        }

        //GetAP
        public APService GetAP(string property, string value)
        {
            try
            {
                AP ap = null;
                APService apSer = new APService();

                if (property == "MAC")
                    ap = DanhMucAP.Instance.GetByMAC(value);
                else if (property == "ID" && value != "")
                    ap = DanhMucAP.Instance.GetByID(Convert.ToInt32(value));

                if (ap != null)
                {
                    apSer.ID = ap.ID;
                    apSer.Name = "";
                    apSer.MAC = ap.MAC.Trim();
                    return apSer;
                }
                else
                    return null;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public APService[] GetAllAPs()
        {
            try
            {
                List<APService> result = new List<APService>();

                foreach (AP ap in DanhMucAP.GetAll())
                {
                    if (ap != null)
                    {
                        APService apSer = new APService();
                        apSer.ID = ap.ID;
                        apSer.Name = "";
                        apSer.MAC = ap.MAC.Trim();
                        result.Add(apSer);
                    }
                }
                return result.ToArray();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public static List<PointLBS> KnnAlgorithm(List<APInfo> listAPOnline, int topAPCalculate)
        {
            //lay ra nhung AP Offline theo Top AP Online da quet duoc, tức là chỉ lọc ra và xét riêng những AP từ phần online thu thập được để tính khoảng cách
            List<DataTable> lsDtOffline = new List<DataTable>();

            foreach (APInfo apInfo in listAPOnline)
            {
                AP ap = DanhMucAP.Instance.GetByMAC(apInfo.MAC);
                //Lấy danh sách tọa độ X,Y với RSS của các AP nêu trên tại các điểm
                //Với method này là full các điểm có trong offline
                DataTable dtAPInfo = DanhMucGroupAP.GetAVGRSSbyName(ap.ID, apInfo.MAC);
                lsDtOffline.Add(dtAPInfo);
            }

            List<ReferencePoint> listRPs = RPsInfo(lsDtOffline, topAPCalculate);
            listRPs = CalculateEuclideDistance(listAPOnline, listRPs);

            List<ReferencePoint> topEuclid = listRPs.OrderBy(x => x.EuclidDistance).Take(_KNN).ToList();  //Muốn trả về bao nhiêu point thì set _KNN
            List<PointLBS> listPoint = new List<PointLBS>();
            foreach (ReferencePoint item in topEuclid)
            {
                PointLBS p = new PointLBS();
                p.ToaDoX = item.ToaDoX;
                p.ToaDoY = item.ToaDoY;
                listPoint.Add(p);
            }

            return listPoint;
        }
        //Sử dụng dữ liệu Clustering: tìm cách tìm vị trí ở cụm nào trước khi tính khoảng cách
        public static List<PointLBS> KnnAlgorithmByClustering(List<APInfo> listAPOnline, int topAPCalculate)
        {
            try
            {
                //test thử thấy cách này ngẫu nhiên --> sai kinh khủng. Sửa lại thành phải tồn tại cả 3 RSS online trong cụm đó thì mới OK
                #region Chọn ra 1 cụm có AVG TOP 3 RSS MAX gần nhất với online

                //Tính AVG top 3 max rss online
                double avgTop3Online = listAPOnline.OrderByDescending(a => a.RSS).Select(x => x.RSS).Take(3).Average();
                APInfo apTop0 = listAPOnline[0];
                APInfo apTop1 = listAPOnline[1];
                APInfo apTop2 = listAPOnline[2];

                //Tính RSS trung bình các cụm dựa theo bảng PointClutered
                DataTable dt = DanhMucPointClustered.GetListClusterAndAVGRSS();
                DataTable dtCluter = new DataTable();

                string clusterIDNearest = ""; //Lưu lại clusterID được chọn
                double min = double.MaxValue;  //Nhớ là các RSS đều là số âm, cần tính trị tuyệt đối
                foreach (DataRow row in dt.Rows)
                {
                    double avgRSSTemp = 0;
                    try
                    {
                        avgRSSTemp = Convert.ToDouble(row["AVGRSS_TOP3MAX"]);
                    }
                    catch (Exception ex)
                    { }

                    if (min > Math.Abs(Math.Abs(avgRSSTemp) - Math.Abs(avgTop3Online)))
                    {
                        //Điều kiện 2, Phải có 3 RSS online trong cum đó
                        //B1: lấy các X,Y trong cụm này ra
                        dtCluter.Clear();
                        dtCluter = DanhMucPointClustered.GetListClusterByClusterID(row["ClusterID_TOP3MAX"].ToString());

                        //Duyệt qua 3 AP TOP, so sánh với X, Y 
                        bool bol1 = false, bol2 = false, bol3 = false;
                        foreach (DataRow rowTemp in dtCluter.Rows)
                        {
                            bol1 = ListAPInfo.CheckAPExistedInPoint(rowTemp["X"].ToString(), rowTemp["Y"].ToString(), apTop0.MAC);
                            bol2 = ListAPInfo.CheckAPExistedInPoint(rowTemp["X"].ToString(), rowTemp["Y"].ToString(), apTop1.MAC);
                            bol3 = ListAPInfo.CheckAPExistedInPoint(rowTemp["X"].ToString(), rowTemp["Y"].ToString(), apTop2.MAC);
                        }

                        if (bol1 && bol2 && bol3)
                        {
                            min = Math.Abs(Math.Abs(avgRSSTemp) - Math.Abs(avgTop3Online));
                            clusterIDNearest = row["ClusterID_TOP3MAX"].ToString();
                        }
                    }
                }

                #endregion
                //Lấy ra danh sách các X, Y trong cụm gần nhất
                dtCluter.Clear();
                dtCluter = DanhMucPointClustered.GetListClusterByClusterID(clusterIDNearest);
                string whereCondition = "";
                string xCondition = "X IN (";
                string yCondition = "Y IN (";

                foreach (DataRow row in dtCluter.Rows)
                {
                    xCondition += row["X"].ToString() + ", ";
                    yCondition += row["Y"].ToString() + ", ";
                }

                if (xCondition.EndsWith(", ")) xCondition = xCondition.Substring(0, xCondition.Length - 2) + ")";
                if (yCondition.EndsWith(", ")) yCondition = yCondition.Substring(0, yCondition.Length - 2) + ")";

                whereCondition = string.Format("{0} AND {1}", xCondition, yCondition);
                //lay ra nhung AP Offline trong 1 cụm theo Top AP Online da quet duoc
                //Bằng cách lấy cụm X

                List<DataTable> lsDtOfflineClutered = new List<DataTable>();

                foreach (APInfo apInfo in listAPOnline)
                {
                    AP ap = DanhMucAP.Instance.GetByMAC(apInfo.MAC);
                    //Lấy danh sách tọa độ X,Y với RSS của các AP nêu trên tại các điểm, lưu trữ dưới dạng DataTable method RPsInfo tính khoảng cách
                    //Với method này là lấy các điểm theo cụm các điểm có trong offline

                    DataTable dtAPInfo = DanhMucGroupAP.GetAVGRSSbyName(ap.ID, apInfo.MAC, whereCondition);
                    lsDtOfflineClutered.Add(dtAPInfo);
                }

                List<ReferencePoint> listRPs = RPsInfo(lsDtOfflineClutered, topAPCalculate);
                listRPs = CalculateEuclideDistance(listAPOnline, listRPs);

                List<ReferencePoint> topEuclid = listRPs.OrderBy(x => x.EuclidDistance).Take(_KNN).ToList();  //Muốn trả về bao nhiêu point thì set _KNN
                List<PointLBS> listPoint = new List<PointLBS>();
                foreach (ReferencePoint item in topEuclid)
                {
                    PointLBS p = new PointLBS();
                    p.ToaDoX = item.ToaDoX;
                    p.ToaDoY = item.ToaDoY;
                    listPoint.Add(p);
                }

                return listPoint;
            }
            catch (Exception ex)
            {
                //MessageBox.Show(ex.Message);
                throw ex;
            }
        }

        //Chuyển từ DataTable sang kiểu ReferencePoint, lọc ra các Point đạt tiêu chuẩn để tính khoảng cach.
        private static List<ReferencePoint> RPsInfo(List<DataTable> lsDtOffline, int topAPCalculate)
        {
            List<ReferencePoint> listRPs = new List<ReferencePoint>();

            int i = 0;
            //Xét với từng AP Off
            foreach (DataTable dt in lsDtOffline)
            {
                //Mỗi AP Off có nhiều dòng cần tính sum

                foreach (DataRow row in dt.Rows)
                {
                    ReferencePoint rpItem = new ReferencePoint();
                    if (i == 0)
                    {
                        if (row["X"] is double && row["Y"] is double && row["RSS"] is double)
                        {
                            rpItem.ToaDoX = (double)row["X"];
                            rpItem.ToaDoY = (double)row["Y"];
                            rpItem.RSS_AP1 = (double)row["RSS"];
                            rpItem.AP1_MAC = (string)row["MAC"];
                            listRPs.Add(rpItem);

                        }
                    }
                    else if (i > 0) //các lần tiếp theo - trừ lần đầu tiên
                    {
                        foreach (ReferencePoint rpUpdate in listRPs)
                        {
                            if (row["X"] is double && row["Y"] is double &&
                                (double)row["X"] == rpUpdate.ToaDoX && (double)row["Y"] == rpUpdate.ToaDoY)
                            {
                                switch (i)
                                {
                                    case 1:
                                        rpUpdate.RSS_AP2 = (double)row["RSS"];
                                        rpUpdate.AP2_MAC = (string)row["MAC"];
                                        break;
                                    case 2:
                                        rpUpdate.RSS_AP3 = (double)row["RSS"];
                                        rpUpdate.AP3_MAC = (string)row["MAC"];
                                        break;
                                    case 3:
                                        rpUpdate.RSS_AP4 = (double)row["RSS"];
                                        rpUpdate.AP4_MAC = (string)row["MAC"];
                                        break;
                                    case 4:
                                        rpUpdate.RSS_AP5 = (double)row["RSS"];
                                        rpUpdate.AP5_MAC = (string)row["MAC"];
                                        break;
                                    case 5:
                                        rpUpdate.RSS_AP6 = (double)row["RSS"];
                                        rpUpdate.AP6_MAC = (string)row["MAC"];
                                        break;
                                    case 6:
                                        rpUpdate.RSS_AP7 = (double)row["RSS"];
                                        rpUpdate.AP7_MAC = (string)row["MAC"];
                                        break;
                                    case 7:
                                        rpUpdate.RSS_AP8 = (double)row["RSS"];
                                        rpUpdate.AP8_MAC = (string)row["MAC"];
                                        break;
                                    case 8:
                                        rpUpdate.RSS_AP9 = (double)row["RSS"];
                                        rpUpdate.AP9_MAC = (string)row["MAC"];
                                        break;
                                    case 9:
                                        rpUpdate.RSS_AP10 = (double)row["RSS"];
                                        rpUpdate.AP10_MAC = (string)row["MAC"];
                                        break;
                                    default:
                                        break;
                                }
                            }
                        }
                    }
                }

                i++;
            }

            //Delete những AP không đạt yêu cầu, tức là cần xét 5AP từ online gửi xuống, nhưng điểm đó chỉ xuất hiện dưới 5AP thì xóa đi
            for (int j = 0; j < listRPs.Count; j++)
            {
                ReferencePoint rpDelete = listRPs[j];
                switch (topAPCalculate)
                {
                    case 1:
                        if (rpDelete.RSS_AP1 == 0)
                            listRPs.Remove(rpDelete);
                        break;
                    case 2:
                        if (rpDelete.RSS_AP1 == 0 || rpDelete.RSS_AP2 == 0)
                            listRPs.Remove(rpDelete);
                        break;
                    case 3:
                        if (rpDelete.RSS_AP1 == 0 || rpDelete.RSS_AP2 == 0 || rpDelete.RSS_AP3 == 0)
                            listRPs.Remove(rpDelete);
                        break;
                    case 4:
                        if (rpDelete.RSS_AP1 == 0 || rpDelete.RSS_AP2 == 0 || rpDelete.RSS_AP3 == 0 || rpDelete.RSS_AP4 == 0)
                            listRPs.Remove(rpDelete);
                        break;
                    case 5:
                        if (rpDelete.RSS_AP1 == 0 || rpDelete.RSS_AP2 == 0 || rpDelete.RSS_AP3 == 0 || rpDelete.RSS_AP4 == 0 || rpDelete.RSS_AP5 == 0)
                            listRPs.Remove(rpDelete);
                        break;
                    default:
                        break;
                }
            }
            return listRPs;
        }
        //Tính khoảng cách Euclide
        private static List<ReferencePoint> CalculateEuclideDistance(List<APInfo> rssOnline, List<ReferencePoint> listRPs)
        {
            try
            {

                foreach (ReferencePoint item in listRPs)
                {
                    double sum = 0;

                    foreach (APInfo online in rssOnline)
                    {
                        if (online.MAC.Trim() == item.AP1_MAC.Trim()) sum += (online.RSS - item.RSS_AP1) * (online.RSS - item.RSS_AP1);
                        if (online.MAC.Trim() == item.AP2_MAC.Trim()) sum += (online.RSS - item.RSS_AP2) * (online.RSS - item.RSS_AP2);
                        if (online.MAC.Trim() == item.AP3_MAC.Trim()) sum += (online.RSS - item.RSS_AP3) * (online.RSS - item.RSS_AP3);
                        if (online.MAC.Trim() == item.AP4_MAC.Trim()) sum += (online.RSS - item.RSS_AP4) * (online.RSS - item.RSS_AP4);
                        if (online.MAC.Trim() == item.AP5_MAC.Trim()) sum += (online.RSS - item.RSS_AP5) * (online.RSS - item.RSS_AP5);
                        if (online.MAC.Trim() == item.AP6_MAC.Trim()) sum += (online.RSS - item.RSS_AP6) * (online.RSS - item.RSS_AP6);
                        if (online.MAC.Trim() == item.AP7_MAC.Trim()) sum += (online.RSS - item.RSS_AP7) * (online.RSS - item.RSS_AP7);
                        if (online.MAC.Trim() == item.AP8_MAC.Trim()) sum += (online.RSS - item.RSS_AP8) * (online.RSS - item.RSS_AP8);
                        if (online.MAC.Trim() == item.AP9_MAC.Trim()) sum += (online.RSS - item.RSS_AP9) * (online.RSS - item.RSS_AP9);
                        if (online.MAC.Trim() == item.AP10_MAC.Trim()) sum += (online.RSS - item.RSS_AP10) * (online.RSS - item.RSS_AP10);
                    }

                    item.EuclidDistance = Math.Sqrt(sum);
                }
                return listRPs;
            }
            catch (Exception ex)
            {
                //MessageBox.Show(ex.Message);
                throw ex;
            }
        }

        //Point result
        public static PointLBS PositionAVG(List<PointLBS> lsKNN)
        {
            PointLBS p = new PointLBS();
            p.ToaDoX = lsKNN.Average(x => x.ToaDoX);
            p.ToaDoY = lsKNN.Average(x => x.ToaDoY);

            return p;
        }

        //Point result chia tam giac theo 4 diem
        public static PointLBS PositionAVG4P(List<PointLBS> lsKNN)
        {

            double tdXr = 0;
            double tdYr = 0;

            if (lsKNN.Count > 0)
            {
                double tdX1 = 0;
                double tdY1 = 0;
                tdX1 = (lsKNN[0].ToaDoX + lsKNN[1].ToaDoX + lsKNN[2].ToaDoX) / 3;
                tdY1 = (lsKNN[0].ToaDoY + lsKNN[1].ToaDoY + lsKNN[2].ToaDoY) / 3;
                double tdX2 = 0;
                double tdY2 = 0;
                tdX2 = (lsKNN[3].ToaDoX + lsKNN[1].ToaDoX + lsKNN[2].ToaDoX) / 3;
                tdY2 = (lsKNN[3].ToaDoY + lsKNN[1].ToaDoY + lsKNN[2].ToaDoY) / 3;
                double tdX3 = 0;
                double tdY3 = 0;
                tdX3 = (lsKNN[0].ToaDoX + lsKNN[1].ToaDoX + lsKNN[3].ToaDoX) / 3;
                tdY3 = (lsKNN[0].ToaDoY + lsKNN[1].ToaDoY + lsKNN[3].ToaDoY) / 3;
                tdXr = (tdX1 + tdX2 + tdX3) / 3;
                tdYr = (tdY1 + tdY2 + tdY3) / 3;
            }

            PointLBS pointResult = new PointLBS();
            pointResult.ToaDoX = tdXr;
            pointResult.ToaDoY = tdYr;
            return pointResult;
        }

        //Sau khi định vị bằng phương pháp KNN xong, tìm xem kết quả, nếu 4 điểm năm nhiều hơn trên cụm nào thì bỏ các điểm nằm ngoài
        //Lấy các góc của cụm gần nhất điền vào
        public static PointLBS PositionAVG5PClutering(List<PointLBS> lsKNN)
        {
            SqlConnection con = new SqlConnection(Common.ConnectionString);
            try
            {
                string whereCondition = "";
                string xIN = "X IN (";
                string yIN = "Y IN (";
                string xNOTIN = "X NOT IN (";
                string yNOTIN = "Y NOT IN (";

                foreach (PointLBS item in lsKNN)
                {
                    xIN += item.ToaDoX + ", ";
                    yIN += item.ToaDoY + ", ";
                    xNOTIN += item.ToaDoX + ", ";
                    yNOTIN += item.ToaDoY + ", ";
                }

                if (xIN.EndsWith(", ")) xIN = xIN.Substring(0, xIN.Length - 2) + ")";
                if (yIN.EndsWith(", ")) yIN = yIN.Substring(0, yIN.Length - 2) + ")";

                if (xNOTIN.EndsWith(", ")) xNOTIN = xNOTIN.Substring(0, xNOTIN.Length - 2) + ")";
                if (yNOTIN.EndsWith(", ")) yNOTIN = yNOTIN.Substring(0, yNOTIN.Length - 2) + ")";

                whereCondition = string.Format("{0} AND {1}", xIN, yIN);

                SqlCommand cmd = con.CreateCommand();
                SqlDataAdapter da = new SqlDataAdapter();

                cmd.CommandText = string.Format("SELECT TOP 1 COUNT(*) SoDiemTrongCum, ClusterID_TOP3MAX FROM PointClustered \n" +
                                                "WHERE {0} \n" +
                                                "GROUP BY ClusterID_TOP3MAX \n" +
                                                "ORDER BY SoDiemTrongCum DESC ", whereCondition);

                da.SelectCommand = cmd;
                DataTable dt = new DataTable();
                da.Fill(dt);

                int soDiemTrongCum = 0, clusterID = 0;
                try
                {
                    soDiemTrongCum = Convert.ToInt32(dt.Rows[0]["SoDiemTrongCum"].ToString());
                }
                catch (Exception ex)
                { }
                try
                {
                    clusterID = Convert.ToInt32(dt.Rows[0]["ClusterID_TOP3MAX"].ToString());
                }
                catch (Exception ex)
                { }

                int soDiemCanThem = 4 - soDiemTrongCum; //Vì cần tối thiểu 4 điểm, thiếu thì lấy thêm trong cụm đó ra cho đủ --> xác suất sai thấp hơn

                //Lấy lại các điểm đầu vào nằm trong cụm được chọn
                DanhMucPointClustered pFromInput = DanhMucPointClustered.Filter(string.Format("ClusterID_TOP3MAX = {0} AND {1} AND {2}", clusterID, xIN, yIN));

                //Lấy ra những điểm trong cụm được chọn, nhưng k nằm trong các điểm đầu vào
                DanhMucPointClustered pTemp = DanhMucPointClustered.Filter(string.Format("ClusterID_TOP3MAX = {0} AND {1} AND {2}", clusterID, xNOTIN, yNOTIN));

                //Nếu soDiemCanThem < 4 --> lấy từ pTemp soDiemCanThem mà gần 1 X nào từ pFromInput. Để đảm bảo các điểm bù vào gần với điểm được chọn nhất
                List<PointLBS> lstNew = new List<PointLBS>();
                foreach (DataRowView dr in pFromInput.DataView)
                {
                    PointLBS pNew = new PointLBS();
                    pNew.ToaDoX = (double)dr["X"];
                    pNew.ToaDoY = (double)dr["Y"];

                    lstNew.Add(pNew);
                }
                if (soDiemCanThem > 0)
                {
                    for (int i = 0; i < soDiemCanThem; i++)
                    {
                        DataRowView dr = pTemp.DataView[i];

                        PointLBS pNew = new PointLBS();
                        pNew.ToaDoX = (double)dr["X"];
                        pNew.ToaDoY = (double)dr["Y"];

                        lstNew.Add(pNew);
                    }
                }

                double tdXr = 0;
                double tdYr = 0;

                if (lstNew.Count > 0)
                {
                    double tdX1 = 0;
                    double tdY1 = 0;
                    tdX1 = (lstNew[0].ToaDoX + lstNew[1].ToaDoX + lstNew[2].ToaDoX) / 3;
                    tdY1 = (lstNew[0].ToaDoY + lstNew[1].ToaDoY + lstNew[2].ToaDoY) / 3;
                    double tdX2 = 0;
                    double tdY2 = 0;
                    tdX2 = (lstNew[3].ToaDoX + lstNew[1].ToaDoX + lstNew[2].ToaDoX) / 3;
                    tdY2 = (lstNew[3].ToaDoY + lstNew[1].ToaDoY + lstNew[2].ToaDoY) / 3;
                    double tdX3 = 0;
                    double tdY3 = 0;
                    tdX3 = (lstNew[0].ToaDoX + lstNew[1].ToaDoX + lstNew[3].ToaDoX) / 3;
                    tdY3 = (lstNew[0].ToaDoY + lstNew[1].ToaDoY + lstNew[3].ToaDoY) / 3;
                    tdXr = (tdX1 + tdX2 + tdX3) / 3;
                    tdYr = (tdY1 + tdY2 + tdY3) / 3;
                }

                PointLBS pointResult = new PointLBS();
                pointResult.ToaDoX = tdXr;
                pointResult.ToaDoY = tdYr;
                return pointResult;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                con.Close();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public PersonData[] getAllPersons()
        {
            SqlConnection dbConn = new SqlConnection(connStr);
            dbConn.Open();
            string sqlSelect = "select * from [users] ";
            SqlDataAdapter da = new SqlDataAdapter(sqlSelect, dbConn);
            DataTable dt = new DataTable();
            SqlCommand dbCommand = new SqlCommand(sqlSelect, dbConn);
            da.Fill(dt);
            dbConn.Close();
            List<PersonData> list = new List<PersonData>();
            foreach (DataRow row in dt.Rows)
            {
                // Person target = Activator.CreateInstance();
                PersonData target = new PersonData();
                target.Name = row["Name"].ToString();
                target.User = row["UserName"].ToString();
                target.Email = row["EMail"].ToString();
                target.Password = row["Password"].ToString();
                // DataColumnAttribute.Bind(row,target);
                list.Add(target);
            }
            return list.ToArray();
        }

        public PersonData[] getJsonPersons()
        {
            return getAllPersons();
        }

        public bool DeletePerson(string user)
        {
            bool returnBool = false;
            SqlConnection dbConn = new SqlConnection(connStr);
            string sqlStr = "DELETE FROM users where username = '" + user + "';";
            SqlCommand dbCommand = new SqlCommand(sqlStr, dbConn);
            try
            {
                dbConn.Open();
                if (dbCommand.ExecuteNonQuery() != 0)
                {
                    returnBool = true;
                }
            }
            catch
            {
                returnBool = false;
            }
            dbConn.Close();
            return returnBool;
        }

        public bool UpdateUser(string user, PersonData pd)
        {
            bool returnBool = false;
            string username, name, email, password;
            username = pd.User;
            name = pd.Name;
            email = pd.Email;
            password = pd.Password;
            SqlConnection dbConn = new SqlConnection(connStr);
            string sqlStr = "UPDATE users SET username = '" + username + "',name = '" + name + "',password = '" + password + "',email= '" + email + "' WHERE username = '" + user + "' ;";
            SqlCommand dbCommand = new SqlCommand(sqlStr, dbConn);
            try
            {
                dbConn.Open();
                if (dbCommand.ExecuteNonQuery() != 0)
                {
                    returnBool = true;
                }
            }
            catch
            {
                returnBool = false;
            }
            dbConn.Close();
            return returnBool;
        }

        public bool UpdateUserPut(string user, RequestData rData)
        {
            bool returnBool = false;
            var data = rData.details.Split('|');
            var pd = new PersonData
            {
                Name = data[0],
                User = data[1],
                Email = data[2],
                Password = data[3]
            };
            string username, name, email, password;
            username = pd.User;
            name = pd.Name;
            email = pd.Email;
            password = pd.Password;
            SqlConnection dbConn = new SqlConnection(connStr);
            string sqlStr = "UPDATE users SET username = '" + username + "',name = '" + name + "',password = '" + password + "',email= '" + email + "' WHERE username = '" + user + "' ;";
            SqlCommand dbCommand = new SqlCommand(sqlStr, dbConn);
            try
            {
                dbConn.Open();
                if (dbCommand.ExecuteNonQuery() != 0)
                {
                    returnBool = true;
                }
                dbConn.Close();
            }
            catch
            {
                returnBool = false;
            }
            return returnBool;
        }

        public bool UpdateUserPost(PersonData pd)
        {
            bool returnBool = false;
            string username, name, email, password;
            username = pd.User;
            name = pd.Name;
            email = pd.Email;
            password = pd.Password;
            SqlConnection dbConn = new SqlConnection(connStr);
            string sqlStr = "UPDATE users SET username = '" + username + "',name = '" + name + "',password = '" + password + "',email= '" + email + "' WHERE username = '" + username + "' ;";
            SqlCommand dbCommand = new SqlCommand(sqlStr, dbConn);
            try
            {
                dbConn.Open();
                if (dbCommand.ExecuteNonQuery() != 0)
                {
                    returnBool = true;
                }
                dbConn.Close();
            }
            catch
            {
                returnBool = false;
            }
            return returnBool;
        }

        public bool AddUser2(RequestData rData)
        {
            bool returnBool = false;

            var data = rData.details.Split('|');
            var response = new PersonData
            {
                Name = data[0],
                User = data[1],
                Email = data[2],
                Password = data[3]
            };

            SqlConnection dbConn = new SqlConnection(connStr);
            string sqlStr = "INSERT INTO users(username,name,email,password) values('" + data[0] + "', '" + data[1] + "', '" + data[2] + "', '" + data[3] + "');";
            SqlCommand dbCommand = new SqlCommand(sqlStr, dbConn);
            try
            {
                dbConn.Open();
                if (dbCommand.ExecuteNonQuery() != 0)
                {
                    returnBool = true;
                }
                returnBool = true;
            }
            catch
            {
                returnBool = false;
            }
            dbConn.Close();
            return returnBool;
        }

        public PersonData TestPersonDataPost(PersonData pd)
        {
            var response = new PersonData
            {
                Name = pd.Name,
                User = pd.User,
                Email = pd.Email,
                Password = pd.Password
            };

            return response;
            // return pd;
        }

        public PersonData JsonTestPersonDataPost(PersonData pd)
        {
            return TestPersonDataPost(pd);
        }

        public string GetRooms(string toaDoX, string toaDoY)
        {
            try
            {
                string result = "";
                Hashtable hash = new Hashtable();

                float X = 0, Y = 0;

                try
                {
                    X = (float)Convert.ToDouble(toaDoX);
                }
                catch (Exception)
                { }
                try
                {
                    Y = (float)Convert.ToDouble(toaDoY);
                }
                catch (Exception)
                { }

                if (X == 0 || Y == 0) return "";

                //Tính khoảng cách tới từng phòng ban
                foreach (Room room in DanhMucRoom.Instance)
                {
                    PointF p1 = new PointF((float)room.X1, (float)room.Y1);
                    PointF p2 = new PointF((float)room.X2, (float)room.Y2);
                    PointF p3 = new PointF((float)room.X3, (float)room.Y3);
                    PointF p4 = new PointF((float)room.X4, (float)room.Y4);
                    List<PointF> polygon = new List<PointF>();
                    polygon.Add(p1);
                    polygon.Add(p2);
                    polygon.Add(p3);
                    polygon.Add(p4);
                    polygon.Add(p1);  //bao giờ cũng add lại p1 để khép kín đa giác

                    PointF pointLocation = new PointF(X, Y);

                    float d = (float)CalculateDistince.CalMinDisctice1PointToPolygon(polygon, pointLocation);

                    if (!hash.ContainsKey(room.Name) && d <= 20)
                    {
                        hash.Add(room.Name, d);
                        result += room.Name + "-";
                    }
                }

                //CalculateDistince.CalMinDisctice1PointToPolygon(

                return result;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        public string GetInfoByRoom(string rName)
        {
            try
            {
                string result = string.Format("Thông tin các sự kiện của phòng {0}@x @n", rName);

                //DanhMucInformationRoom.Instance.LoadFromDB();

                DanhMucInformationRoom dmInfo = DanhMucInformationRoom.Filter(string.Format("RoomName = '{0}' AND '{1}' <= EndDate ",
                                                                                rName, Common.DateTimeSQLToString(DateTime.Now)));
                if (dmInfo.Count > 0)
                {
                    foreach (InformationRoom info in dmInfo)
                    {
                        string startDate = "", endDate = "";
                        if (info.StartDate != null) startDate = Common.DateTimeVNToString((DateTime)info.StartDate);
                        if (info.EndDate != null) endDate = Common.DateTimeVNToString((DateTime)info.EndDate);
                        result += string.Format("{0}@x{1} đến {2}@n", info.Infor, startDate, endDate);
                    }
                }
                else
                {
                    result += "Không có sự kiện nào sắp diễn ra";
                }

                if (result.EndsWith("@n")) result = result.Substring(0, result.Length - 2);

                return result;
            }
            catch (Exception ex)
            {

                throw ex;
            }
        }
        //Trả về kết quả định vị
        public ResultData GetPoint(string apOnline)
        {
            List<APInfo> listAPOnline = new List<APInfo>();

            var data = apOnline.Split('=');
            var ToaDoSend = data[data.Count() - 1].Split(';');
            for (int i = 0; i < data.Length - 1; i++)
            {
                try
                {
                    var ap = data[i].Split('_');
                    APInfo apItem = new APInfo();
                    AP getAP = DanhMucAP.Instance.GetByMAC(ap[0]);

                    //Check AP phải trong CSDL
                    if (getAP != null)
                    {
                        apItem.ID = getAP.ID;
                        apItem.Name = getAP.Name;
                        apItem.MAC = ap[0];
                        apItem.RSS = Convert.ToInt32(ap[1].ToString());
                        apItem.Percent = 0;

                        if (listAPOnline.Count < _TopAP_RSSmax)
                            listAPOnline.Add(apItem);
                    }
                }
                catch (Exception)
                {
                }
            }

            List<PointLBS> listPoint = new List<PointLBS>();

            _topAPCalculate = _KNN;

            //Nếu dùng dữ liệu bình thường
            //listPoint = KnnAlgorithm(listAPOnline, _topAPCalculate);
            //PointLBS pointAVG = PositionAVG4P(listPoint);

            ////Nếu dùng dữ liệu phân cụm, Phương án 1
            //Stopwatch sw = Stopwatch.StartNew();
            //listPoint = KnnAlgorithmByClustering(listAPOnline, _topAPCalculate);
            //decimal time = sw.ElapsedMilliseconds;
            //sw.Stop();

            //Nếu dùng dữ liệu phân cụm, Phương án 2
            _KNN = 5;   //Lấy 5 điểm để dễ phân biệt nằm trong cụm nào nhiều nhất
            listPoint = KnnAlgorithm(listAPOnline, _topAPCalculate);
            Stopwatch sw1 = Stopwatch.StartNew();
            PointLBS pointAVG4Diem = PositionAVG4P(listPoint);
            decimal time1 = sw1.ElapsedMilliseconds;
            sw1.Stop();

            Stopwatch sw2 = Stopwatch.StartNew();
            PointLBS pointAVG = PositionAVG5PClutering(listPoint);
            decimal time2 = sw2.ElapsedMilliseconds;
            sw2.Stop();
            //listPoint.Add(pointAVG);  //Chi add 1 item --> de k phai chinh service tren android

            ResultData result = new ResultData();
            result.ToaDoX = pointAVG.ToaDoX;
            result.ToaDoY = pointAVG.ToaDoY;

            if (!ToaDoSend[0].Equals("") && !ToaDoSend[1].Equals(""))
            {
                KetQua toado = DanhMucKetQua.Instance.NewDoiTuong();
                toado.Xsend = Convert.ToDecimal(ToaDoSend[0].ToString());
                toado.Ysend = Convert.ToDecimal(ToaDoSend[1].ToString());
                toado.Xrecei = (decimal)pointAVG4Diem.ToaDoX;
                toado.Yrecei = (decimal)pointAVG4Diem.ToaDoY;
                toado.Xkalman = (decimal)pointAVG.ToaDoX;
                toado.Ykalman = (decimal)pointAVG.ToaDoY;
                toado.TimeExcute_recei = time1;
                toado.TimeExcute_kal = time2;
                toado.InsertToDB();
            }

            //Get rooms nếu k được thì bỏ qua, k hiện lỗi
            try
            {
                result.roomsShowMessage = GetRooms(pointAVG.ToaDoX.ToString(), pointAVG.ToaDoY.ToString());
            }
            catch (Exception ex)
            { }

            //Trả về kết quả
            listPoint.Add(pointAVG);  //Chi add 1 item --> de k phai chinh service tren android
            return result;
        }
        public ResultData GetPointKalman(string apOnline, string Lold_str, string Pold_str)
        {
            //Convert string to matrix
            //L kích thước 2x1. Định dạng x1,x2
            //P kích thước 2x2. Định dạng x1,x2,x3,x4
            double[,] Lold = new double[2, 1];
            double[,] Pold = new double[2, 2];
            string[] temp = new string[10];

            temp = Lold_str.Split(',');
            Lold[0, 0] = Convert.ToDouble(temp[0]);
            Lold[1, 0] = Convert.ToDouble(temp[1]);

            temp = Pold_str.Split(',');
            Pold[0, 0] = Convert.ToDouble(temp[0]);
            Pold[0, 1] = Convert.ToDouble(temp[1]);
            Pold[1, 0] = Convert.ToDouble(temp[2]);
            Pold[1, 1] = Convert.ToDouble(temp[3]);

            //
            List<APInfo> listAPOnline = new List<APInfo>();

            var data = apOnline.Split('=');
            var ToaDoSend = data[data.Count() - 1].Split(';');
            for (int i = 0; i < data.Length - 1; i++)
            {
                try
                {
                    var ap = data[i].Split('_');
                    APInfo apItem = new APInfo();
                    AP getAP = DanhMucAP.Instance.GetByMAC(ap[0]);

                    //Check AP phải trong CSDL
                    if (getAP != null)
                    {
                        apItem.ID = getAP.ID;
                        apItem.Name = getAP.Name;
                        apItem.MAC = ap[0];
                        apItem.RSS = Convert.ToInt32(ap[1].ToString());
                        apItem.Percent = 0;

                        if (listAPOnline.Count < _TopAP_RSSmax)
                            listAPOnline.Add(apItem);
                    }
                }
                catch (Exception)
                {
                }
            }

            List<PointLBS> listPoint = new List<PointLBS>();

            _topAPCalculate = _KNN;

            listPoint = KnnAlgorithm(listAPOnline, _topAPCalculate);
            //PointLBS pointAVG = PositionAVG(listPoint);
            PointLBS pointAVG = PositionAVG4P(listPoint);

            //listPoint.Add(pointAVG);  //Chi add 1 item --> de k phai chinh service tren android

            //Đoạn này sử dụng kalman
            double[,] inputKalman = KalmanSolver.ConvertToMatrix(pointAVG.ToaDoX, pointAVG.ToaDoY);
            //  _Lold = inputKalman;
            double[,] w = new double[2, 1] { { -2 }, { 1
                                                     } };
            double[,] l_predict = KalmanSolver.l_predict(Lold, w);
            double[,] Q = new double[2, 2] { { 1, 0 }, { 0, 1 } };
            double[,] P_predict = KalmanSolver.P_predict(Pold, Q);
            double[,] R = new double[2, 2] { { 1, 0 }, { 0, 1 } };
            double[,] KalmanGain = KalmanSolver.kalmanGain(P_predict, R);

            double[,] P_adjusted = KalmanSolver.P_adjusted(P_predict, KalmanGain);
            double[,] l_adjusted = KalmanSolver.l_adjusted(l_predict, KalmanGain, inputKalman);


            PointLBS pointResult = new PointLBS();
            pointResult.ToaDoX = l_adjusted[0, 0];
            pointResult.ToaDoY = l_adjusted[1, 0];
            if (!ToaDoSend[0].Equals("") && !ToaDoSend[1].Equals(""))
            {
                KetQua toado = DanhMucKetQua.Instance.NewDoiTuong();
                toado.Xsend = Convert.ToDecimal(ToaDoSend[0].ToString());
                toado.Ysend = Convert.ToDecimal(ToaDoSend[1].ToString());
                toado.Xrecei = (decimal)pointAVG.ToaDoX;
                toado.Yrecei = (decimal)pointAVG.ToaDoY;
                toado.Xkalman = (decimal)l_adjusted[0, 0];
                toado.Ykalman = (decimal)l_adjusted[1, 0];
                toado.InsertToDB();
            }
            //Convert matrix to string để trả về cho di động
            //L kích thước 2x1. Định dạng x1,x2
            //P kích thước 2x2. Định dạng x1,x2,x3,x4
            string Lcurrent = l_adjusted[0, 0] + "," + l_adjusted[1, 0];
            string Pcurrent = P_adjusted[0, 0] + "," + P_adjusted[0, 1] + "," + P_adjusted[1, 0] + "," + P_adjusted[1, 1];

            temp = Lold_str.Split(',');
            Lold[0, 0] = Convert.ToDouble(temp[0]);
            Lold[1, 0] = Convert.ToDouble(temp[1]);

            temp = Pold_str.Split(',');
            Pold[0, 0] = Convert.ToDouble(temp[0]);
            Pold[0, 1] = Convert.ToDouble(temp[1]);
            Pold[1, 0] = Convert.ToDouble(temp[2]);
            Pold[1, 1] = Convert.ToDouble(temp[3]);

            ResultData result = new ResultData();
            result.ToaDoX = pointResult.ToaDoX;
            result.ToaDoY = pointResult.ToaDoY;
            result.l = Lcurrent;
            result.p = Pcurrent;

            //Trả về kết quả
            listPoint.Add(pointResult);  //Chi add 1 item --> de k phai chinh service tren android
            return result;
        }
    }
}